



import * as THREE from './build/three.module.js';
import { GUI } from './jsm/libs/dat.gui.module.js';

import { TrackballControls } from "./jsm/controls/TrackballControls.js";
import { VertexNormalsHelper } from "./jsm/helpers/VertexNormalsHelper.js";

import { MTLLoader } from "./jsm/loaders/MTLLoader.js";
import { MtlObjBridge } from "./jsm/loaders/obj2/bridge/MtlObjBridge.js";
import { OBJLoader2 } from "./jsm/loaders/OBJLoader2.js";
import { OBJLoader2Parallel } from "./jsm/loaders/OBJLoader2Parallel.js";
import { LoadedMeshUserOverride } from "./jsm/loaders/obj2/shared/MeshReceiver.js";
import * as TWEEN  from '/tween.js'
//压缩工具函数
var ZipTools = (function () {

    function ZipTools(path, vue) {
        this.zip = new JSZip();
        this.vue = vue;

        this.fileLoader = new THREE.FileLoader();
        this.fileLoader.setPath(path);
        this.fileLoader.setResponseType('arraybuffer');

        this.zipContent = null;
    }

    ZipTools.prototype.load = function (filename, callbacks) {
        var scope = this;

        var onSuccess = function (zipDataFromFileLoader) {
            scope.zip.loadAsync(zipDataFromFileLoader)
                .then(function (zip) {

                    scope.zipContent = zip;
                    callbacks.success();

                });
        };

        var refPercentComplete = 0;
        var percentComplete = 0;
        var output;
        var onProgress = (event) => {
            if (!event.lengthComputable) return;

            percentComplete = Math.round(event.loaded / event.total * 100);
            if (percentComplete > refPercentComplete) {

                refPercentComplete = percentComplete;

                output = '正在下载  "' + filename + '": ' + percentComplete + '%';
                this.vue.handProcess(output)
                // console.log(output);
                if (Boolean(callbacks.progress)) callbacks.progress(output);

            }
        };

        var onError = function (event) {
            var output = 'Error of type "' + event.type + '" occurred when trying to load: ' + filename;
            console.error(output);
            callbacks.error(output);
        };
        this.vue.handProcess(`开始下载${filename}`)
        this.fileLoader.load(filename, onSuccess, onProgress, onError);
    };

    ZipTools.prototype.unpackAsUint8Array = function (filename, callback) {

        if (JSZip.support.uint8array) {

            this.zipContent.file(filename).async('uint8array')
                .then(function (dataAsUint8Array) {

                    callback(dataAsUint8Array);

                });

        } else {

            this.zipContent.file(filename).async('base64')
                .then(function (data64) {

                    callback(new TextEncoder('utf-8').encode(data64));

                });

        }
    };

    ZipTools.prototype.unpackAsString = function (filename, callback) {
        this.zipContent.file(filename).async('string')
            .then(function (dataAsString) {

                callback(dataAsString);

            });
    };

    return ZipTools;

})();
console.log(TWEEN.default.Tween)
window. tween = new TWEEN.default.Tween({x: 100, y: 100, rotation: 0})
				
const WWOBJLoader2Example = function (elementToBindTo) {
    this.renderer = null;
    this.canvas = elementToBindTo;
    this.aspectRatio = 1;
    this.recalcAspectRatio();

    this.scene = null;
    this.cameraDefaults = {
        posCamera: new THREE.Vector3(0.0, 175.0, 500.0),
        posCameraTarget: new THREE.Vector3(0, 0, 0),
        near: 0.1,
        far: 10000,
        fov: 45
    };
    this.camera = null;
    this.cameraTarget = this.cameraDefaults.posCameraTarget;

    this.controls = null;

    this.flatShading = true;
    this.doubleSide = true;
    this.useJsmWorker = true;
    this.loadCount = 6;

    this.pivot = null;
};

WWOBJLoader2Example.prototype = {

    constructor: WWOBJLoader2Example,

    initGL: function () {
        this.renderer = new THREE.WebGLRenderer({
            canvas: this.canvas,
            antialias: true,
            autoClear: true
        });
        this.renderer.setClearColor(0xffffff);
        this.renderer.setPixelRatio(window.devicePixelRatio);

        this.scene = new THREE.Scene();

        this.camera = new THREE.PerspectiveCamera(this.cameraDefaults.fov, this.aspectRatio, this.cameraDefaults.near, this.cameraDefaults.far);
        this.resetCamera();
        this.controls = new TrackballControls(this.camera, this.renderer.domElement);
        this.controls.rotateSpeed = 0.3;// 旋转速度
        this.controls.zoomSpeed = 0.3;// 缩放速度
        this.controls.panSpeed = 0.3;// 平controls


        this.controls.staticMoving = false;// 静止移动，为 true 则没有惯性
        this.controls.dynamicDampingFactor = 0.2;// 阻尼系数 越小 则滑动越大

        this.controls.minDistance = 300; // 最小视角
        this.controls.maxDistance = 1000;// 最大视角 Infinity 无穷大

        let ambientLight = new THREE.AmbientLight(0x222222);
        let directionalLight1 = new THREE.DirectionalLight(0xffffff);
        let directionalLight2 = new THREE.DirectionalLight(0xffffff);
        let directionalLight3 = new THREE.DirectionalLight(0xffffff);
        directionalLight1.position.set(-100, -50, 100);
        directionalLight2.position.set(100, 50, -100);
        directionalLight3.position.set(0, 200, 0);
        this.scene.add(directionalLight1);
        this.scene.add(directionalLight2);
        this.scene.add(directionalLight3);
        this.scene.add(ambientLight);

        let helper = new THREE.GridHelper(1200, 30, 0xFF4444, 0x404040);
        helper.material.opacity = 0.1;
        helper.material.depthWrite = false;
        helper.material.transparent = true;
        this.scene.add(helper);


        // materials

        this. bodyMaterial = new THREE.MeshPhysicalMaterial({
            color: 0xff0000, metalness: 0.6, roughness: 0.4, clearcoat: 0.05, clearcoatRoughness: 0.05
        });

        // this. detailsMaterial = new THREE.MeshStandardMaterial({
        //     color: 0xffffff, metalness: 1.0, roughness: 0.5
        // });

        this. glassMaterial = new THREE.MeshPhysicalMaterial({
            color: 0x000000, metalness: 0, roughness: 0.1, transmission: 0.9, transparent: true
        });

        this. bodyColorInput = document.getElementById('body-color');
        this.bodyColorInput.addEventListener('input', function () {

            app.bodyMaterial.color.set(this.value);

        });

        // this. detailsColorInput = document.getElementById('details-color');
        // this.detailsColorInput.addEventListener('input', function () {

        //     app.detailsMaterial.color.set(this.value);

        // });

        this. glassColorInput = document.getElementById('glass-color');
        this.glassColorInput.addEventListener('input', function () {

            app. glassMaterial.color.set(this.value);

        });


        this.pivot = new THREE.Object3D();
        this.pivot.name = 'Pivot';
        this.scene.add(this.pivot);
    },

    useTesila: function () {
        if(!app.scene.children[5].getObjectByName('tesila')){
            let modelName = 'tesila';
            this._reportProgress({ detail: { text: "载入Tesla_Model_3_2018中请稍后" } });
    
            let objLoader2 = new OBJLoader2()
                .setModelName(modelName);
    
            let scope = this;
            function onLoadMtl(mtlParseResult) {
                objLoader2.addMaterials(MtlObjBridge.addMaterialsFromMtlLoader(mtlParseResult), true);
    
                let fileLoader = new THREE.FileLoader();
                fileLoader.setPath('');
                fileLoader.setResponseType('arraybuffer');
                // fileLoader.load('models/Tesla_Model_3_2018_obj/Tesla_Model_3.obj',
                fileLoader.load('models/Tesla_Model_3_2018_obj/Tesla_Model_3.obj',
                    function (content, message) {
                        let local = new THREE.Object3D();
                        local.name = 'tesila';
                        local.position.set(0, 0, 0);
                        local.rotation.x = 11;
                        local.scale.x=2;
                        local.scale.y=2;
                        local.scale.z=2;
                        scope.pivot.add(local);
                        local.add(objLoader2.parse(content));
                        let bodycolor=objLoader2.parse(content);
                        for(let i=0;i<bodycolor.children.length;i++){
                            bodycolor.getObjectByName( 'body_02_pivot' ).material.color = app.bodyMaterial.color;
                            bodycolor.getObjectByName('d_glass_01_pivot').material.color=app.glassMaterial.color;
                        }
    
                         scope._reportProgress({ detail: { text: "" } });
                        scope.finalize();
                    }
                );
            }
    
            let mtlLoader = new MTLLoader();
            mtlLoader.load('models/Tesla_Model_3_2018_obj/Tesla_Model_3.mtl', onLoadMtl);
        }
       
    },

    // useParseParallel: function () {
    //     let modelName = 'female02_vertex' ;
    //     this._reportProgress( { detail: { text: 'Loading: ' + modelName } } );

    //     let local = new THREE.Object3D();
    //     local.name = 'Pivot_female02_vertex';
    //     local.position.set( -75, 0, 0 );
    //     this.pivot.add( local );

    //     let scope = this;
    //     function callbackOnLoad( object3d, message ) {
    //         local.add( object3d );
    //         scope._reportProgress( { detail: { text: 'Loading of ' + modelName + ' completed: ' + message } } );
    //         scope.finalize();
    //     }

    //     let materials = {
    //         tester: new THREE.MeshStandardMaterial()
    //     };

    //     let objLoader2Parallel = new OBJLoader2Parallel()
    //         .setModelName( modelName )
    //         .setJsmWorker( this.useJsmWorker, new URL( OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH, window.location.href ) )
    //         .setCallbackOnLoad( callbackOnLoad )
    //         .addMaterials( materials, true );

    //     let fileLoader = new THREE.FileLoader();
    //     fileLoader.setPath( '' );
    //     fileLoader.setResponseType( 'arraybuffer' );
    //     fileLoader.load( 'models/obj/female02/female02_vertex_colors.obj',
    //         function ( content ) {
    //             objLoader2Parallel.parse( content );
    //         }
    //     );
    // },

    useVolo: function () {
        let modelName = 'volo';
        this._reportProgress({ detail: { text: 'Loading: ' + modelName } });

        let objLoader2 = new OBJLoader2()
            .setModelName(modelName)
            .setUseIndices(true);

        let scope = this;
        function callbackOnLoad(object3d, message) {
            let local = new THREE.Object3D();
            local.name = 'volo';
            local.rotation.x = 11;
            local.position.set(0, 1300, 0);
            local.rotation.z = 3.1;
            scope.pivot.add(local);
            local.add(object3d);

            scope._reportProgress({ detail: { text: 'Loading of ' + modelName + ' completed: ' + message } });
            scope.finalize();
        }

        function onLoadMtl(mtlParseResult) {
            objLoader2.addMaterials(MtlObjBridge.addMaterialsFromMtlLoader(mtlParseResult), true);
            objLoader2.load('models/volvo_obj/v40cc.obj', callbackOnLoad, null, null, null);
        }

        let mtlLoader = new MTLLoader();
        mtlLoader.load('models/volvo_obj/v40cc.mtl', onLoadMtl);
    },

    useLoadParallel: function () {
        let modelName = 'WaltHead';
        this._reportProgress({ detail: { text: 'Loading: ' + modelName } });

        let local = new THREE.Object3D();
        local.name = 'Pivot_WaltHead';
        local.position.set(-175, 50, 0);
        let scale = 0.5;
        local.scale.set(scale, scale, scale);
        this.pivot.add(local);

        let objLoader2Parallel = new OBJLoader2Parallel()
            .setModelName(modelName)
            .setJsmWorker(this.useJsmWorker, new URL(OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH, window.location.href));

        let scope = this;
        function callbackOnLoad(object3d, message) {
            local.add(object3d);
            scope._reportProgress({ detail: { text: 'Loading of ' + modelName + ' completed: ' + message } });
            scope.finalize();
        }
        function onLoadMtl(mtlParseResult) {
            objLoader2Parallel.addMaterials(MtlObjBridge.addMaterialsFromMtlLoader(mtlParseResult), true);
            objLoader2Parallel.load('models/obj/walt/WaltHead.obj', callbackOnLoad);
        }

        let mtlLoader = new MTLLoader();
        mtlLoader.load('models/obj/walt/WaltHead.mtl', onLoadMtl);
    },

    useLoadMainFallback: function () {
        let local = new THREE.Object3D();
        local.name = 'Pivot_Cerberus';
        local.position.set(0, 0, 100);
        let scale = 50;
        local.scale.set(scale, scale, scale);
        this.pivot.add(local);

        let objLoader2Parallel = new OBJLoader2Parallel()
            .setModelName(local.name)
            .setExecuteParallel(false);

        let scope = this;
        function callbackOnLoad(object3d, message) {
            local.add(object3d);
            scope._reportProgress({ detail: { text: 'Loading of ' + objLoader2Parallel.modelName + ' completed: ' + message } });
            scope.finalize();
        }

        objLoader2Parallel.load('models/obj/cerberus/Cerberus.obj', callbackOnLoad);
    },

    useLoadParallelMeshAlter: function () {
        let local = new THREE.Object3D();
        local.position.set(175, -100, 0);
        local.name = 'Pivot_ninjaHead';
        this.pivot.add(local);

        let objLoader2Parallel = new OBJLoader2Parallel()
            .setModelName(local.name)
            .setJsmWorker(this.useJsmWorker, new URL(OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH, window.location.href))
            .setBaseObject3d(local);

        // Configure WorkerExecutionSupport to not disregard worker after execution
        objLoader2Parallel.getWorkerExecutionSupport().setTerminateWorkerOnLoad(false);

        function callbackMeshAlter(event) {
            let override = new LoadedMeshUserOverride(false, true);

            let mesh = new THREE.Mesh(event.detail.bufferGeometry, event.detail.material);
            mesh.name = event.detail.meshName;
            let helper = new VertexNormalsHelper(mesh, 2, 0x00ff00);
            helper.name = 'VertexNormalsHelper';

            override.addMesh(mesh);
            override.addMesh(helper);

            return override;
        }
        objLoader2Parallel.setCallbackOnMeshAlter(callbackMeshAlter);

        let scope = this;
        function callbackOnLoad(object3d, message) {
            scope._reportProgress({ detail: { text: 'Loading of ' + objLoader2Parallel.modelName + ' completed: ' + message } });
            scope.finalize();
        }

        objLoader2Parallel.load('models/obj/ninja/ninjaHead_Low.obj', callbackOnLoad);
    },

    finalize: function () {
        this.loadCount--;
        if (this.loadCount === 0) {

            this._reportProgress({ detail: { text: '' } });

        }
    },

    _reportProgress: function (event) {
        let output = '';
        if (event.detail !== null && event.detail !== undefined && event.detail.text) {

            output = event.detail.text;

        }
        console.log('Progress: ' + output);
        document.getElementById('feedback').innerHTML = output;
    },

    resizeDisplayGL: function () {
        this.controls.handleResize();

        this.recalcAspectRatio();
        this.renderer.setSize(this.canvas.offsetWidth, this.canvas.offsetHeight, false);

        this.updateCamera();
    },

    recalcAspectRatio: function () {
        this.aspectRatio = (this.canvas.offsetHeight === 0) ? 1 : this.canvas.offsetWidth / this.canvas.offsetHeight;
    },

    resetCamera: function () {
        this.camera.position.copy(this.cameraDefaults.posCamera);
        this.cameraTarget.copy(this.cameraDefaults.posCameraTarget);

        this.updateCamera();
    },

    updateCamera: function () {
        this.camera.aspect = this.aspectRatio;
        this.camera.lookAt(this.cameraTarget);
        this.camera.updateProjectionMatrix();
    },

    render: function () {
        if (!this.renderer.autoClear) this.renderer.clear();

        this.controls.update();

        this.renderer.render(this.scene, this.camera);
    },

    alterShading: function () {
        let scope = this;
        scope.flatShading = !scope.flatShading;
        console.log(scope.flatShading ? 'Enabling flat shading' : 'Enabling smooth shading');

        scope.traversalFunction = function (material) {
            material.flatShading = scope.flatShading;
            material.needsUpdate = true;
        };
        function scopeTraverse(object3d) {
            scope.traverseScene(object3d);
        }
        scope.pivot.traverse(scopeTraverse);
    },

    alterDouble: function () {
        let scope = this;
        scope.doubleSide = !scope.doubleSide;
        console.log(scope.doubleSide ? 'Enabling THREE.DoubleSide materials' : 'Enabling THREE.FrontSide materials');

        scope.traversalFunction = function (material) {
            material.side = scope.doubleSide ? THREE.DoubleSide : THREE.FrontSide;
        };

        function scopeTraverse(object3d) {
            scope.traverseScene(object3d);
        }
        scope.pivot.traverse(scopeTraverse);
    },

    traverseScene: function (object3d) {
        if (Array.isArray(object3d.material)) {

            let materials = object3d.material.materials;
            for (let name in materials) {

                if (materials.hasOwnProperty(name)) this.traversalFunction(materials[name]);

            }

        } else if (object3d.material) {

            this.traversalFunction(object3d.material);

        }
    },

    executeLoading: function () {
        // Load a file with OBJLoader2.parse on main
        // this.useParseMain();

        // Load a file with OBJLoader2Parallel.parse in parallel in worker
        // this.useParseParallel();

        // Load a file with OBJLoader.load on main
        this.useLoadMain();

        // Load a file with OBJLoader2Parallel.load in parallel in worker
        this.useLoadParallel();

        // Load a file with OBJLoader2Parallel.load on main with fallback to OBJLoader2.parse
        this.useLoadMainFallback();

        // Load a file with OBJLoader2Parallel.load in parallel in worker and add normals during onMeshAlter
        this.useLoadParallelMeshAlter();
    }

};

window.app = new WWOBJLoader2Example(document.getElementById('example'));

let handleExecuteLoading;
let wwObjLoader2Control = {
    flatShading: app.flatShading,
    doubleSide: app.doubleSide,
    useJsmWorker: app.useJsmWorker,
    blockEvent: function (event) {

        event.stopPropagation();

    },
    disableElement: function (elementHandle) {

        elementHandle.domElement.addEventListener('click', this.blockEvent, true);
        elementHandle.domElement.parentElement.style.pointerEvents = 'none';
        elementHandle.domElement.parentElement.style.opacity = 0.5;

    },
    executeLoading: function () {
        app.useTesila();
        // app.executeLoading();
        // this.disableElement(handleExecuteLoading);

    },
    loadSuv: function () {
        app.useVolo();
    }
};

let menuDiv = document.getElementById('dat');
let gui = new GUI({
    autoPlace: false,
    width: 120
});
menuDiv.appendChild(gui.domElement);

// let folderRenderingOptions = gui.addFolder('Rendering Options');
// let controlFlat = folderRenderingOptions.add(wwObjLoader2Control, 'flatShading').name('Flat Shading');
// controlFlat.onChange(function (value) {
//     console.log('Setting flatShading to: ' + value);
//     app.alterShading();
// });

// let controlDouble = folderRenderingOptions.add(wwObjLoader2Control, 'doubleSide').name('Double Side Materials');
// controlDouble.onChange(function (value) {
//     console.log('Setting doubleSide to: ' + value);
//     app.alterDouble();
// });

// let folderObjLoader2ParallelOptions = gui.addFolder('OBJLoader2Parallel Options');
// let controlJsmWorker = folderObjLoader2ParallelOptions.add(wwObjLoader2Control, 'useJsmWorker').name('Use Module Workers');
// controlJsmWorker.onChange(function (value) {
//     console.log('Setting useJsmWorker to: ' + value);
//     app.useJsmWorker = value;
// });
let folderExecution = gui.addFolder('车型选择');
handleExecuteLoading = folderExecution.add(wwObjLoader2Control, 'executeLoading').name('特斯拉');
handleExecuteLoading = folderExecution.add(wwObjLoader2Control, 'loadSuv').name('volo');
handleExecuteLoading.domElement.id = 'startButton';
// folderRenderingOptions.open();
// folderObjLoader2ParallelOptions.open();
folderExecution.open();


// init three.js example application
function resizeWindow() {
    app.resizeDisplayGL();
}

function render() {
    requestAnimationFrame(render);
    app.render();
}
window.addEventListener('resize', resizeWindow, false);

console.log('Starting initialisation phase...');
app.initGL();
app.resizeDisplayGL();

// kick render loop
render();

